using System;
using System.Linq;

namespace ReactiveLang
{
    partial class Expression
    {
        internal abstract class Notification<T>
        {
            public class OnValue : Notification<T>
            {
                public readonly T Value;
                public OnValue(T value)
                {
                    Value = value;
                }
                public override void Accept(IExpressionObserver<T> observer)
                {
                    observer.OnValue(Value);
                }
                public override string ToString()
                {
                    return "value { " + Value + " }";
                }
            }
            public class OnException : Notification<T>
            {
                public readonly Exception Exception;
                public OnException(Exception ex)
                {
                    Exception = ex;
                }
                public override void Accept(IExpressionObserver<T> observer)
                {
                    observer.OnException(Exception);
                }
                public override string ToString()
                {
                    return "exception { " + Exception + " }";
                }
            }

            public abstract void Accept(IExpressionObserver<T> observer);
        }

        internal static IExpression<Notification<T>> ToNotifications<T>(this IExpression<T> expression)
        {
            return CreateWithDisposable<Notification<T>>(o => expression.Activate(
                onValue: x => o.OnValue(new Notification<T>.OnValue(x)),
                onException: ex => o.OnValue(new Notification<T>.OnException(ex))
            ));
        }
    }
}